闲话 22.10.4
闲话
今日休息
所以我看着一堆人在打PCK
“码力是很重要的”
所以我没去打
于是今天的杂题有两道!
写完这句话后开了第三题 发现这是nmd结论题
于是今天的杂题有三道
我是什么废物两个小时实现不出来这个结论
于是今天的杂题还是两道
行吧我题读错了 怪不得我模不出样例
所以今天的杂题还是三道
似乎上次自由时间我写了 4 道题来着
所以我在退步(确信)
晚饭回来更新:
路上在躲跑餐的学生们
然后往旁边一躲
脚下躺着的楼号牌:不好意思,这里满员了
然后踩了上去
然后一滑
膝盖:Full Combo~
70億の秘密と同じだけの
純粋が欲しくなるのは何故?
何が正義か
そんな馬鹿正直なふたりが
わからないよと泣いてる
杂题
蓝智力相当高,尤其擅长数学。据说连人类所无法想象程度的计算都能够在瞬间完成。——《东方求闻史纪》
定义 表示严格大于 的最小的完全平方数,定义 为小于等于 的最大的完全平方数。例如,。蓝认为,一个正整数是“可爱”的,当且仅当 ,例如, 是可爱的正整数,而 不是。
蓝给了你一个长度为 的正整数数列 ,你需要帮她找到最小的非负整数 ,使得 , 是可爱的。
打表题。性质题。
观察 打表 经过严密的数学证明可得,可爱的数组成了一段段区间,第 段区间可以表为 。
当 位于第 段区间内时定能得到答案,因此 。
假设 被放在了第 段内。可以发现 共有 种取值。
当 变化时,可能存在原来是可爱数的 变为不可爱的数,反之亦然。
当一个元素的性质发生变化时,就无法通过 的继续变化使得其性质发生第二次变化。这是因为 段后的所有段长度定 ,其长度大于 可能的变化范围。
可以发现,这其实限制了 的上下界。
我们初始时令 位于第 段的段首。然后我们向后扫每一段
对于可爱段,我们找到这段内最大的数,这个数标定了 取值的上界,因为不能让这个数出可爱段。对于不可爱段,我们找到这段内最小的数,这个数标定了 取值的下界,因为需要让这个数增加到离开不可爱段。
于是我们每次扫一下就能得到答案。
这么写的复杂度似乎是 ,具体是不是线性没想。
code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
const int N = 1e6 + 10;
int n, a[N], vis[N<<2], nxt[N<<2], pref[N<<2];
signed main() {
ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
cin >> n; rep(i,1,n) cin >> a[i];
rep(i,2,n) vis[a[i] - a[1]] = 1;
nxt[4000001] = 1e7, pref[0] = -1;
rep(i,1,4000000) if (vis[i]) pref[i] = i; else pref[i] = pref[i-1];
pre(i,4000000,1) if (vis[i]) nxt[i] = i; else nxt[i] = nxt[i+1];
rep(i,1,a[n]) {
if (i * (i+1) < a[1]) continue;
int l = 0, r = i; if (a[1] > i * i) l = a[1] - i * i;
int nowl = 0, nowr = i;
for (int j = i ; ; j++) {
if (pref[nowr] >= nowl) r = min(r, nowr - pref[nowr]);
nowl += 2 * j + 1;
if (nxt[nowr+1] < nowl) l = max(l, nowl - nxt[nowr+1]);
nowr += 2 * j + 2;
if (l > r or nowl > a[n] - a[1]) break;
}
if (l <= r) {
cout << i * i + l - a[1] << '\n';
return 0;
}
}
}
给定两个 的 矩阵 和 ,定义一次操作为交换 中任意两个相邻的位置中的值,输出使得 的最小操作次数,如果无法使 则输出 。
.
贪心题。
当矩阵是 的时候,答案是易求的。
设 ,则最终答案就是
证明考虑 那边多 个 1 的情况,直到 那边出现 1 为止都得带着这 个 1 一直移动,移动一格的花费是 。 多 1 的情况同理,因此加绝对值。
现在矩阵是 的了,我们需要得到上下交换的最小花费。
分别记录两个前缀和 与 分别表示两矩阵第一行的前缀和之差与第二行的前缀和之差。
在当前情况下上下交换当且仅当 与 异号。当同号时上下交换是不必要的,这时交换肯定不会使答案更优。
异号时应当上下移动至 与 之一为 0。这样做可以使得全局左右交换的次数最少,肯定不会使答案更劣。
上下移动后应当在答案中加入 ,原因同 理。
记得开ll。
code
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
#define sgn(u) ((u == 0) ? 0 : (u > 0) ? 1 : -1 )
const int N = 2e5 + 10;
int n, a[2][N], b[2][N];
long long cnt, ans;
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
rep(i,0,1) rep(j,1,n) cin >> a[i][j], cnt += a[i][j];
rep(i,0,1) rep(j,1,n) cin >> b[i][j], cnt -= b[i][j];
if (cnt) { cout << -1 << '\n'; return 0; }
long long sum0 = 0, sum1 = 0, delt;
rep(i,1,n) {
sum0 += a[0][i] - b[0][i], sum1 += a[1][i] - b[1][i];
if (1ll * sum0 * sum1 < 0) {
delt = min(abs(sum0), abs(sum1));
ans += delt;
sum0 += -sgn(sum0) * delt;
sum1 += -sgn(sum1) * delt;
}
ans += abs(sum0) + abs(sum1);
} cout << ans << endl;
}
给定一个长度为 的括号序列 ,保证其由 个左括号
(
和 个右括号)
组成。定义一次操作是翻转 的一个连续子串。请求出最少几次操作可将 转换为合法括号序列。输出最少的操作次数,并构造一种方案。可以证明,这总是能在 次操作中完成。。
结论题。
注意这里的操作定义是这样的:设我们用 数组从下标 1 位置开始存储这个序列,则对 序列的操作等价于 reverse(str+l,str+r+1)
。无论如何操作,左括号和右括号的数量不会发生变化,因此 恒等于 。
括号序列的转化是 (
,)
,合法括号序列是任意位置非负。
设括号序列 的前缀和数组为 。若 则不需要操作,此后讨论默认 不是合法括号序列。
我们断言,使用不超过两次操作就可以得到合法括号序列。
证明
我们只需要找到前缀和数组的最大值 ,随后翻转 与 即可。
设翻转后的前缀和数组为 。
当 时, 对应的是原序列 段的和,即 。由于 最大,因此此情况下 。
当 时, 对应的是原序列 段和 段的和,即 ,其中 为 翻转后对应位置。由于 且 最大,因此此情况下 。
因此我们只需要判断是否能仅操作一次。
令 分别为最前和最后一个 小于 的位置。我们断言,最终翻转的区间 需要满足 ,并且最优选择一定是 最大的 与 最大的 r。不保证最优选择在操作后一定得到合法括号序列。
证明
可以知道最终 和 的前缀和没有变化。这表明最终翻转的区间 需要满足 。
考察 段新的前缀和 ,立即列出方程:,其中 为 翻转后对应位置。
则当 即 时有操作一次即可得到合法括号序列。
我们只需要贪心地选择最大值即可得到最优选择。
选择后只需要检验一次,若可行则输出 1,若不可行则输出 2。
构造方案平凡,上方已给出。
总时间复杂度 。
code
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
const int N = 4e5 + 10;
int T, n, mpos, pref[N];
char ch[N];
bool check(int l, int r) {
reverse(ch+l, ch+r+1);
rep(i,l,r) {
pref[i] = pref[i-1] + (ch[i] == '(' ? 1 : -1);
if (pref[i] < 0) return false;
}
rep(i,r+1,n) {
pref[i] = pref[i-1] + (ch[i] == '(' ? 1 : -1);
if (pref[i] < 0) return false;
}
return true;
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> T;
while (T--) {
cin >> n >> ch + 1; n <<= 1;
bool completed = true; mpos = 1; pref[n+1] = -1e9;
rep(i,1,n) {
pref[i] = pref[i-1] + (ch[i] == '(' ? 1 : -1);
if (pref[mpos] < pref[i]) mpos = i;
if (pref[i] < 0) completed = false;
}
if (completed) { cout << 0 << '\n'; continue; };
int lmst = 1, rmst = n;
while (lmst <= n and pref[lmst] >= 0) lmst ++;
while (rmst > 0 and pref[rmst] >= 0) rmst --;
int lck = n+2, rck = n+1;
rep(i,1,lmst) if (pref[lck-1] < pref[i-1]) lck = i;
rep(i,rmst+1,n) if (pref[rck] < pref[i]) rck = i;
if (check(lck, rck)) {
cout << 1 << '\n';
cout << lck << ' ' << rck << '\n';
}
else {
cout << 2 << '\n';
cout << 1 << ' ' << mpos << '\n';
cout << mpos+1 << ' ' << n << '\n';
}
}
}
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat221004.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)